﻿using KinonekoSoftware.Foundation.Languages;
using KinonekoSoftware.Foundation.Patterns;
using KinonekoSoftware.Foundation.UI.ViewModels;
using KinonekoSoftware.Platform.Languages;

namespace KinonekoSoftware.Platform.Controls
{
    public partial class DialogHost
    {

        #region DialogContext

        private          DialogBase        _last;
        private          DialogBase        _current;
        private readonly Stack<DialogBase> _stack;
        private readonly Dictionary<Type, int>      _ViewModelErrorTypeTracker;

        #endregion

        #region ShowDialog

        public async Task<Result<T>> ShowDialog<T>(DialogContext context, ObjectDialog<T> dialog)
        {
            if (dialog is null)
            {
                // 空检测
                return Result<T>.Failed(
                    LanguageManager.GetText(
                                            TextSR.Dialog_Instance_Null));
            }

            if (dialog.IsInitialized)
            {
                // 对话框视图模型不允许重复使用
                return Result<T>.Failed(
                    LanguageManager.GetText(
                        TextSR.Dialog_Instance_NotAllowReuse));
            }

            context ??= new DialogContext();

            //
            // 准备手续
            Prepare(context, dialog);

            //
            //
            _current = dialog;

            //
            // send to ui thread
            PushDialog(dialog);

            return await dialog.TaskCompletionSource
                               .Task;
        }
        
        
        public async Task<Result<T>> ShowDialog<T>(DialogContext context, AsyncObjectDialog<T> dialog)
        {
            if (dialog is null)
            {
                // 空检测
                return Result<T>.Failed(
                    LanguageManager.GetText(
                        TextSR.Dialog_Instance_Null));
            }

            if (dialog.IsInitialized)
            {
                // 对话框视图模型不允许重复使用
                return Result<T>.Failed(
                    LanguageManager.GetText(
                        TextSR.Dialog_Instance_NotAllowReuse));
            }

            context ??= new DialogContext();

            //
            // 准备手续
            Prepare(context, dialog);

            //
            //
            _current = dialog;

            //
            // send to ui thread
            PushDialog(dialog);

            return await dialog.TaskCompletionSource
                               .Task;
        }

        public async Task<bool> ShowDialog(DialogContext context, BooleanDialog dialog)
        {
            if (dialog is null)
            {
                // 空检测
                return false;
            }

            if (dialog.IsInitialized)
            {
                // 对话框视图模型不允许重复使用
                return false;
            }


            //
            // 准备手续
            Prepare(context, dialog);

            //
            //
            _current = dialog;


            //
            // send to ui thread
            PushDialog(dialog);

            return await dialog.TaskCompletionSource
                               .Task;
        }
        
        

        public async Task<TripleSelection> ShowDialog(TripleSelectionViewModel dialog, string description, string option1Text, string option2Text)
        {
            if (dialog is null)
            {
                // 空检测
                return TripleSelection.Failed;
            }

            if (dialog.IsInitialized)
            {
                // 空检测
                return TripleSelection.Failed;
            }


            var dc = new DialogContext();
            dc.Set(DialogContext.Key_Option1ButtonText, option1Text);
            dc.Set(DialogContext.Key_Option2ButtonText, option2Text);
            dc.Set(DialogContext.Key_Description, description);

            //
            // 准备手续
            Prepare(dc, dialog);

            //
            //
            _current = dialog;


            //
            // send to ui thread
            PushDialog(dialog);

            return await dialog.TaskCompletionSource
                               .Task;
        }


        public Task ShowDialog(DialogContext context, NotifyDialog dialog)
        {
            if (dialog is null)
            {
                // 空检测
                return Task.FromException(new ArgumentNullException(nameof(dialog)));
            }

            if (dialog.IsInitialized)
            {
                // 对话框视图模型不允许重复使用
                return Task.FromException(new InvalidOperationException(nameof(dialog)));
            }


            //
            // 准备手续
            Prepare(context, dialog);

            //
            //
            _current = dialog;


            //
            // send to ui thread
            PushDialog(dialog);

            return dialog.TaskCompletionSource
                         .Task;
        }


        private void PushDialog(ManagedLifetimeObject dialog)
        {
            Xplat.RunOnUIThread(() =>
            {
                Control v = null;
                
                if (dialog is ViewModelBase fs && fs.EnableViewCache)
                {
                    if (fs.ViewCache is not null && fs.ViewCache
                                                      .TryGetTarget(out var cacheV))
                    {
                        v = (Control)cacheV;
                    }
                    else
                    {
                        v            = Xplat.Associate(dialog);
                        fs.ViewCache = new WeakReference<object>(v);
                    }
                }
                else
                {
                    v = Xplat.Associate(dialog);
                }

                //
                // Show
                Dialog = v;

                //
                // raise dialog
                IsOpened = true;

                Focus();
            });
        }

        #endregion

        private void OnHandlingUnDispatchedException(DialogBase dc, Exception ex)
        {
            var t = dc.GetType();

            if (_ViewModelErrorTypeTracker.TryGetValue(t, out var err))
            {
                err++;
                _ViewModelErrorTypeTracker[t] = err;
            }
            else
            {
                _ViewModelErrorTypeTracker.TryAdd(t, 1);
            }

            //
            // 创建一个临时的对话框
            var temp = new InternalErrorDialogVM(ex, t);
            temp.Receive(new DialogContext
            {
                CloseHandler = CloseDialogImpl,
            });
            PushDialog(temp);
        }

        private void CloseDialogImpl(DialogBase dc)
        {
            if (_current is null)
            {
                return;
            }

            if (!ReferenceEquals(_current, dc) &&
                dc.GetType() != typeof(InternalErrorDialogVM))
            {
                throw new InvalidOperationException(
                    LanguageManager.GetText(TextSR.Dialog_Instance_NotEqual));
            }

            //
            //
            _current.Stop();

            if (_last is null)
            {
                //
                // send to ui thread
                Xplat.RunOnUIThread(() =>
                {
                    IsOpened = false;
                    Dialog   = null;
                });
                _current = null;
                return;
            }

            _current = _last;

            if (_stack.Count > 0)
            {
                _last = _stack.Pop();
            }
            else
            {
                _last = null;
            }

            //
            //
            _current.Resume();

            //
            // send to ui thread
            Xplat.RunOnUIThread(() =>
            {
                Control v;

                if (_current.ViewCache is not null &&
                    _current.ViewCache.TryGetTarget(out var tempV))
                {
                    v = (Control)tempV;
                }
                else
                {
                    v = Xplat.Associate(_current);
                }

                IsOpened = false;
                Dialog   = null;

                //
                // Show
                Dialog = v;

                //
                // raise dialog
                IsOpened = true;
            });
        }

        private void Prepare(DialogContext context, ManagedLifetimeObject vm)
        {
            if (_current is not null &&
                _last is null)
            {
                _current.Suspend();
                _last = _current;
            }
            else if (_current is not null &&
                _last is not null)
            {
                _current.Suspend();
                _stack.Push(_last);
                _last = _current;
            }

            //
            //
            context.CloseHandler     = CloseDialogImpl;
            context.ExceptionHandler = OnHandlingUnDispatchedException;

            //
            // 
            vm.Receive(context);
        }

        /// <summary>
        /// 对话框大小
        /// </summary>
        public int DialogElementCount
        {
            get
            {
                return _stack.Count +
                       (_last is null ? 0 : 1) +
                       (_current is null ? 0 : 1);
            }
        }
        
        public void CloseAllDialog()
        {
            _current?.CancelCommand?.Execute(null);
            _last?.CancelCommand?.Execute(null);

            while (_stack.Count > 0)
            {
                var d = _stack.Pop();
                d?.CancelCommand?.Execute(null);
            }

            IsOpened = false;
            Dialog   = null;
        }
    }
}